#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <atomic>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <boost/algorithm/string.hpp>

namespace ns_util
{
    class TimeUilt
    {
    public:
        static std::string GetTimestamp()
        {
            struct timeval tv;
            gettimeofday(&tv, nullptr);

            return std::to_string(tv.tv_sec);
        }

        // 获取毫秒级时间戳
        static std::string GetTimeMs()
        {
            struct timeval tv;
            gettimeofday(&tv, nullptr);

            return std::to_string(tv.tv_sec * 1000 + tv.tv_usec / 1000);
        }
    };

    const std::string temp_path = "../temp/";
    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &file_name, const std::string &suffix)
        {
            std::string path_name = temp_path + file_name + suffix;
            //std::cout << "path_name: " << path_name << std::endl;
            return path_name;
        }

        // 编译时需要的临时文件
        // 构建源文件路径 + 后缀的完整文件名
        static std::string Src(const std::string &file_name)
        {
            return AddSuffix(file_name, ".cpp");
        }

        static std::string Exe(const std::string &file_name)
        {
            return AddSuffix(file_name, ".exe");
        }

        static std::string compile_stderr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".compile_stderr");
        }

        // 运行时需要的临时文件
        // 构建原文件路径 + 后缀的 完整文件名
        static std::string Stdin(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdin");

        }

        static std::string Stdout(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdout");

        }

        static std::string Stderr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stderr");

        }
    };

    class FileUtil
    {
    public:
        static bool IsFileExists(const std::string &path_name)
        {
            struct stat statbuf;
            if(stat(path_name.c_str(), &statbuf) == 0)
            {
                return true;
            }
            return false;
        }

        static std::string UniqFileName()
        {
            static std::atomic_uint id;
            id++;

            // 毫秒级时间戳 + 原子性递增唯一值，来保证唯一值
            return TimeUilt::GetTimeMs() + "_" + std::to_string(id);
        }

        static bool WriteFile(const std::string &file_name, const std::string &code)
        {
            int fd = open(file_name.c_str(), O_CREAT | O_WRONLY, 0644);
            //std::cout << "file_name: " << file_name << std::endl;
            //std::cout << "fd: " << fd << std::endl;
            if(fd < 0)
                return false;
            
            ssize_t size = write(fd, code.c_str(), code.size());
            //std::cout << "size: " << size << std::endl;
            close(fd);
            if(size != code.size())
                return false;
            return true;
        }

        // static bool ReadFile(const std::string &file_name, std::string *out, bool flag = false)
        // {

        // }

        // static bool WriteFile(const std::string &file_name, const std::string &code)
        // {
        //     std::cout << "源文件名：" << file_name << std::endl;
        //     std::ofstream out(file_name);
        //     if(!out.is_open())
        //         return false;
            
        //     out.write(code.c_str(), code.size());
        //     out.close();
        //     return true;
        // }

        static bool ReadFile(const std::string &file_name, std::string *out, bool flag = false)
        {
            std::ifstream in(file_name);
            if(!in.is_open())
                return false;
            
            std::string line;
            while(getline(in, line))
            {
                *out += line;
                *out += (flag ? "\n" : "");
            }
            in.close();
            return true;
        }
    };

    class StringUtil
    {
    public:
        static void StringSpilt(const std::string &str, std::vector<std::string> &out, const std::string &step)
        {
            boost::split(out, str, boost::is_any_of(step), boost::algorithm::token_compress_off);
        }
    };
}